package com.runa.monitor.platinterface.netservice.equipment;

import com.runa.monitor.comm.dto.Point;
import com.runa.monitor.comm.dto.PointValue;
import com.runa.monitor.platinterface.base.async.FutureDataTask;
import com.runa.monitor.platinterface.netservice.connect.IRequest;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.protocol.dto.*;
import com.runa.protocol.enums.*;
import com.runa.protocol.util.ByteUtil;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * 西门子plc（目前只实现s7部分协议）
 */
public class SmsPlcService extends NormalPlcService {

    private boolean init;

    public SmsPlcService(Integer id, int slaveId, Integer limit, boolean tcpAsync, Integer timeout, ModbusType modbusType, String ip, int port, FutureDataTask task) {
        super(id, slaveId, limit, tcpAsync, timeout, modbusType, ip, port, task);
    }

    @Override
    public void init(List<Point> points) throws Exception {
        pointConvector(points).stream()
                .collect(Collectors.groupingBy(point -> ((S7Point)point).getArea()))
                .forEach(((area, s7Points) -> {
                    s7Points.forEach(point -> allPoints.put(point.getId(), point));
                    constructReadRequest(area, s7Points, allReadRequests, ALL_READ_PRIORITY, 0);
                }));
    }

    private void constructReadRequest0(S7Enum.Area area, List<IPoint> points, List<IRequest<IRequestData>> collective, int ...flag) {
        COTPSectionData cotpSectionData = new COTPSectionData(COTPType.DataTransport);
        if (area == S7Enum.Area.DATA_BLOCK) {
            S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
            requestData.setFunCode(S7Enum.FunCode.READ);
            List<IPoint> reqPoints = new ArrayList<>();
            points.stream().collect(Collectors.groupingBy(point -> ((S7Point)point).getDbNumber()))
                    .forEach((number, dbPoints) -> {
                        dbPoints.sort(Comparator.comparingInt(IPoint::getAddress));
                        S7Point prePoint = null;
                        S7Point startPoint = (S7Point) dbPoints.get(0);
                        for (IPoint ref : dbPoints) {
                            reqPoints.add(ref);
                            S7Point point = (S7Point) ref;
                            if (point == dbPoints.get(dbPoints.size() - 1)) {
                                dbSection(area, number, requestData, point, startPoint);
                                break;
                            }
                            if (prePoint != null) {
                                int pc = point.getByteCount();
                                boolean section = point.getAddress() + pc - startPoint.getAddress() >= this.limit;
                                if (section) {
                                    dbSection(area, number, requestData, prePoint, startPoint);
                                    startPoint = point;
                                }
                            }
                            prePoint = point;
                        }
                    });
            if (!requestData.getParamItems().isEmpty()) {
                collective(collective, reqPoints, requestData, flag);
            }
        } else {
            points.sort(Comparator.comparingInt(IPoint::getAddress));
            S7Point prePoint = null;
            S7Point startPoint = (S7Point) points.get(0);
            List<IPoint> sectionPoints = new ArrayList<>();
            for (IPoint ref : points) {
                S7Point point = (S7Point) ref;
                if (prePoint != null) {
                    int pc = point.getByteCount();
                    boolean section = point.getAddress() + pc - startPoint.getAddress() >= this.limit;
                    if (section) {
                        int count = prePoint.getAddress() - startPoint.getAddress() + prePoint.getByteCount();
                        S7ParamItem item = new S7ParamItem(S7Enum.Variable.BYTE, count, 0, area, startPoint.getAddress(), 0);
                        S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
                        requestData.setFunCode(S7Enum.FunCode.READ);
                        requestData.getParamItems().add(item);
                        startPoint = point;

                        IRequest<IRequestData> request = createReq(requestData);
                        request.flag(flag);
                        collective.add(request);
                        request.collective(collective);
                        requestPointTable.put(request, sectionPoints);
                        sectionPoints = new ArrayList<>();
                    }
                }
                if (point == points.get(points.size() - 1)) {
                    int count = point.getAddress() - startPoint.getAddress() + point.getByteCount();
                    S7ParamItem item = new S7ParamItem(S7Enum.Variable.BYTE, count, 0, area, startPoint.getAddress(), 0);
                    S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
                    requestData.setFunCode(S7Enum.FunCode.READ);
                    requestData.getParamItems().add(item);
                    collective(collective, sectionPoints, requestData, flag);
                }
                prePoint = point;
                sectionPoints.add(prePoint);
            }
        }
    }

    private void constructReadRequest(S7Enum.Area area, List<IPoint> points, List<IRequest<IRequestData>> collective, int ...flag) {
        if (area == S7Enum.Area.DATA_BLOCK) {
            points.stream().collect(Collectors.groupingBy(point -> ((S7Point)point).getDbNumber()))
                    .forEach((number, dbPoints) -> {
                        COTPSectionData cotpSectionData = new COTPSectionData(COTPType.DataTransport);
                        dbPoints.sort(Comparator.comparingInt(IPoint::getAddress));
                        S7Point prePoint = null;
                        S7Point startPoint = (S7Point) dbPoints.get(0);
                        List<IPoint> sectionPoints = new ArrayList<>();
                        for (IPoint ref : dbPoints) {
                            S7Point point = (S7Point) ref;
                            if (prePoint != null) {
                                int pc = point.getByteCount();
                                boolean section = point.getAddress() + pc - startPoint.getAddress() >= this.limit;
                                if (section) {
                                    S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
                                    requestData.setFunCode(S7Enum.FunCode.READ);
                                    dbSection(area, number, requestData, prePoint, startPoint);
                                    collective(collective, sectionPoints, requestData, flag);
                                    startPoint = point;
                                    sectionPoints = new ArrayList<>();
                                }
                            }
                            if (point == dbPoints.get(dbPoints.size() - 1)) {
                                S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
                                requestData.setFunCode(S7Enum.FunCode.READ);
                                dbSection(area, number, requestData, point, startPoint);
                                collective(collective, sectionPoints, requestData, flag);
                            }
                            prePoint = point;
                            sectionPoints.add(point);
                        }
                    });
        } else {
            COTPSectionData cotpSectionData = new COTPSectionData(COTPType.DataTransport);
            points.sort(Comparator.comparingInt(IPoint::getAddress));
            S7Point prePoint = null;
            S7Point startPoint = (S7Point) points.get(0);
            List<IPoint> sectionPoints = new ArrayList<>();
            for (IPoint ref : points) {
                S7Point point = (S7Point) ref;
                if (prePoint != null) {
                    int pc = point.getByteCount();
                    boolean section = point.getAddress() + pc - startPoint.getAddress() >= this.limit;
                    if (section) {
                        int count = prePoint.getAddress() - startPoint.getAddress() + prePoint.getByteCount();
                        S7ParamItem item = new S7ParamItem(S7Enum.Variable.BYTE, count, 0, area, startPoint.getAddress(), 0);
                        S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
                        requestData.setFunCode(S7Enum.FunCode.READ);
                        requestData.getParamItems().add(item);
                        startPoint = point;

                        IRequest<IRequestData> request = createReq(requestData);
                        request.flag(flag);
                        collective.add(request);
                        request.collective(collective);
                        requestPointTable.put(request, sectionPoints);
                        sectionPoints = new ArrayList<>();
                    }
                }
                if (point == points.get(points.size() - 1)) {
                    int count = point.getAddress() - startPoint.getAddress() + point.getByteCount();
                    S7ParamItem item = new S7ParamItem(S7Enum.Variable.BYTE, count, 0, area, startPoint.getAddress(), 0);
                    S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
                    requestData.setFunCode(S7Enum.FunCode.READ);
                    requestData.getParamItems().add(item);
                    collective(collective, sectionPoints, requestData, flag);
                }
                prePoint = point;
                sectionPoints.add(prePoint);
            }
        }
    }

    private void collective(List<IRequest<IRequestData>> collective, List<IPoint> dbPoints, S7RequestData requestData, int[] flag) {
        IRequest<IRequestData> request = createReq(requestData);
        request.flag(flag);
        collective.add(request);
        request.collective(collective);
        requestPointTable.put(request, dbPoints);
    }

    private void dbSection(S7Enum.Area area, Integer number, S7RequestData requestData, S7Point prePoint, S7Point startPoint) {
        int count = prePoint.getAddress() - startPoint.getAddress() + prePoint.getByteCount();
        S7ParamItem item = new S7ParamItem(S7Enum.Variable.BYTE, count, number, area, startPoint.getAddress(), 0);
        requestData.getParamItems().add(item);
    }

    private List<IPoint> pointConvector(List<Point> points) throws Exception {
        List<IPoint> s7Points = new ArrayList<>();
        for (Point point : points) {
            S7Enum.Area area = null;
            int dbNum = 0;
            int address = 0;
            if (point.getAddress().startsWith("I")) {
                area = S7Enum.Area.INPUT;
                address = Integer.parseInt(point.getAddress().substring(1));
            } else if (point.getAddress().startsWith("Q")) {
                area = S7Enum.Area.OUTPUT;
                address = Integer.parseInt(point.getAddress().substring(1));
            } else if (point.getAddress().startsWith("M")) {
                area = S7Enum.Area.MERKER;
                address = Integer.parseInt(point.getAddress().substring(1));
            } else if (point.getAddress().startsWith("L")) {
                area = S7Enum.Area.LOCAL_DATA;
                address = Integer.parseInt(point.getAddress().substring(1));
            } else if (point.getAddress().startsWith("V")) {
                area = S7Enum.Area.DATA_BLOCK;
                dbNum = 1;
                address = Integer.parseInt(point.getAddress().substring(1));
            } else if (point.getAddress().startsWith("DB")) {
                area = S7Enum.Area.DATA_BLOCK;
                int div = point.getAddress().indexOf(".");
                dbNum = Integer.parseInt(point.getAddress().substring(2, div));
                address = Integer.parseInt(point.getAddress().substring(div + 1));
            }
            if (area != null) {
                s7Points.add(new S7Point(point.getId(),
                        point.getCode(), ModbusDataType.valuesOf(point.getDataType()), area,
                        dbNum, address, ByteOrder.valueOf(point.getByteOrder()), point.getOffset()));
            }
        }
        return s7Points;
    }

    @Override
    public void collect(Integer increKey) {
        if (init) {
            super.collect(increKey);
        }
    }

    private Lock rwlock = new ReentrantLock();

    private Condition condition = rwlock.newCondition();

    public synchronized Map<String, Object> query(List<Integer> pointIds) {
        List<IPoint> points = new ArrayList<>();
        for (Integer id : pointIds) {
            S7Point point = (S7Point) allPoints.get(id);
            if (point != null) {
                points.add(point);
            }
        }
        if (points.size() < pointIds.size()) {
            Map<String, Object> result = new HashMap<>();
            result.put("status", "查询失败，下列点位不存在: " + pointIds.stream().filter(
                    id -> !points.stream().map(IPoint::getId)
                            .collect(Collectors.toList()).contains(id)).collect(Collectors.toList()));
            return result;
        }
        points.sort(Comparator.comparingInt(IPoint::getAddress));
        List<IRequest<IRequestData>> pointReadRequests = new ArrayList<>();
        try {
            points.stream().collect(Collectors.groupingBy(point -> ((S7Point)point).getArea()))
                    .forEach(((area, aPoints) ->
                            constructReadRequest(area, aPoints, pointReadRequests, POINT_READ_PRIORITY, increment())));
        } catch (Exception e) {
            Map<String, Object> result = new HashMap<>();
            result.put("status", e.getMessage());
            return result;
        }
        if (pointReadRequests.isEmpty()) {
            Map<String, Object> result = new HashMap<>();
            result.put("status", "查询失败，请求列表为空");
            return result;
        }
        Map<String, Object> values = null;
        sendRequest(pointReadRequests);
        queryStamp.set(System.currentTimeMillis());
        while (values == null) {
            if (System.currentTimeMillis() - queryStamp.get() > (getTimeout() * 2) * pointReadRequests.size()) {
                values = new HashMap<>();
                values.put("status", "请求超时");
                break;
            }
            values = (Map<String, Object>) reqResp(pointReadRequests);
        }
        return values;
    }

    public synchronized Map<String, Object> constructAndSendWriteRequest(List<PointValue> pointValues) {
        List<S7Point> points = new ArrayList<>();
        //从点位列表中获取要下发的点位
        for (PointValue pointValue : pointValues) {
            S7Point point = (S7Point) allPoints.get(pointValue.getId());
            setPointValue(point, pointValue.getValue());
            points.add(point);
        }
        Map<String, Object> result = new HashMap<>();
        if (pointValues.size() > points.size()) {
            result.put("status", "下发失败，下列点位不存在: " + pointValues.stream().filter(
                    pv -> !points.stream().map(S7Point::getId)
                            .collect(Collectors.toList()).contains(pv.getId())).collect(Collectors.toList()));
            return result;
        }
        List<IRequest<IRequestData>> writeRequest = new ArrayList<>();
        points.stream().collect(Collectors.groupingBy(S7Point::getArea))
                .forEach(((area, wPoints) -> {
                    if (area == S7Enum.Area.DATA_BLOCK) {
                        wPoints.stream().collect(Collectors.groupingBy(S7Point::getDbNumber))
                                .forEach((dbNum, dbPoints) -> pointsToRequest(area, dbNum, writeRequest, dbPoints));
                    } else {
                        pointsToRequest(area, 0, writeRequest, points);
                    }
                }));
        if (writeRequest.isEmpty()) {
            result.put("status", "下发失败，请求列表为空");
            return result;
        }
        //发送请求
        sendRequest(writeRequest);
        updateStamp.set(System.currentTimeMillis());
        String status = null;
        while (status == null) {
            if (System.currentTimeMillis() - updateStamp.get() > (getTimeout() * 2) * writeRequest.size()) {
                result.put("status", "请求超时");
                break;
            }
            status = writeResult;
        }
        writeResult = null;
        result.put("status", status);
        return result;
    }

    private void setPointValue(S7Point point, String value) {
        Object object = null;
        switch (point.getDataType()) {
            case Modbus_Bit:
            case Modbus_Boolean:
                object = Boolean.valueOf(value);
                break;
            case Modbus_Int8:
            case Modbus_UInt8:
            case Modbus_Int16:
            case Modbus_UInt16:
            case Modbus_Int32:
            case Modbus_UInt32:
            case Modbus_Float:
            case Modbus_Double:
                object = new BigDecimal(value);
                break;
            default:
        }
        point.constructValue(object);
    }

    private void pointsToRequest(S7Enum.Area area, int dbNumber, List<IRequest<IRequestData>> requests, List<S7Point> points) {
        if (points.isEmpty()) {
            return;
        }
        Iterator<S7Point> iterator = points.iterator();
        List<S7Point> bitPoints = new ArrayList<>();
        while (iterator.hasNext()) {
            S7Point point = iterator.next();
            if (point.getDataType() == ModbusDataType.Modbus_Boolean) {
                bitPoints.add(point);
                iterator.remove();
            }
        }
        //根据地址升序排列
        points.sort(Comparator.comparingInt(S7Point::getAddress));
        S7Point prePoint = null;
        List<S7Point> mpnn = new ArrayList<>();
        List<List<S7Point>> mpnnn = new ArrayList<>();
        //构造连续点位序列
        for (S7Point point : points) {
            if (prePoint != null) {
                if (point.getAddress() - prePoint.getAddress()
                        > prePoint.getByteCount()) {
                    mpnnn.add(mpnn);
                    mpnn = new ArrayList<>();
                }
            }
            mpnn.add(point);
            prePoint = point;
        }
        mpnnn.add(mpnn);
        //每组连续的点位构造一个写请求
        int flag = increment();
        for (List<S7Point> list : mpnnn) {
            if (list.isEmpty()) {
                continue;
            }
            int beginAddress = list.get(0).getAddress();
            S7Point lastPoint = list.get(list.size() - 1);
            int endAddress = lastPoint.getAddress();
            COTPSectionData cotpSectionData = new COTPSectionData(COTPType.DataTransport);
            S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
            requestData.setFunCode(S7Enum.FunCode.WRITE);
            byte[] bytes = new byte[endAddress - beginAddress + lastPoint.getByteCount()];
            for (S7Point point : list) {
                switch (point.getDataType()) {
                    case Modbus_Int8:
                    case Modbus_UInt8:
                        bytes[point.getAddress()-beginAddress] = (byte) point.getValue();
                        break;
                    case Modbus_Int16:
                    case Modbus_UInt16:
                        ByteUtil.shortToByte((Short)point.getValue(), bytes, point.getAddress()-beginAddress, point.getByteOrder());
                        break;
                    case Modbus_Int32:
                    case Modbus_UInt32:
                        ByteUtil.intToByte((Integer)point.getValue(), bytes, point.getAddress()-beginAddress, point.getByteOrder());
                        break;
                    case Modbus_Float:
                        ByteUtil.floatToByte((Float)point.getValue(), bytes, point.getAddress()-beginAddress, point.getByteOrder());
                    case Modbus_Double:
                        //TODO
                        break;
                    default:
                }
            }
            S7ParamItem paramItem = new S7ParamItem(S7Enum.Variable.BYTE, bytes.length, dbNumber, area, beginAddress, 0);
            S7DataItem dataItem = new S7DataItem(S7Enum.ReturnCode.RESERVED, S7Enum.TransportSize.BYTE, bytes.length*8);
            dataItem.setData(bytes);
            requestData.getParamItems().add(paramItem);
            requestData.getDataItems().add(dataItem);
            IRequest<IRequestData> request = createReq(requestData);
            request.collective(requests);
            request.flag(POINT_CTRL_PRIORITY, flag);
            requests.add(request);
        }
        for (S7Point point : bitPoints) {
            COTPSectionData cotpSectionData = new COTPSectionData(COTPType.DataTransport);
            S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
            requestData.setFunCode(S7Enum.FunCode.WRITE);
            S7ParamItem paramItem = new S7ParamItem(S7Enum.Variable.BIT, 1, dbNumber, area, point.getAddress(), point.getDeviation());
            S7DataItem dataItem = new S7DataItem(S7Enum.ReturnCode.RESERVED, S7Enum.TransportSize.BIT, 1);
            dataItem.setData(new byte[]{(byte) (((Boolean)point.getValue()) ? 1: 0)});
            requestData.getParamItems().add(paramItem);
            requestData.getDataItems().add(dataItem);
            IRequest<IRequestData> request = createReq(requestData);
            request.collective(requests);
            request.flag(POINT_CTRL_PRIORITY, flag);
            requests.add(request);
        }
    }

    @Override
    public void handlerReadData(IRequest<IRequestData> request) {
        S7ResponseData responseData = (S7ResponseData) request.getResponse().getResponseData();
        if (responseData.getCotpSectionData().getCotpType() == COTPType.DataTransport) {
            if (responseData.getFunCode() == S7Enum.FunCode.READ) {
                if (!responseData.getData().isEmpty()) {
                    List<IPoint> points = requestPointTable.get(request);
                    s7PointValue(points, responseData.getData());
                    List<IRequest<IRequestData>> collective = request.collective();
                    for (IRequest<IRequestData> req : collective) {
                        if (!req.beReady()) {
                            return;
                        }
                    }
                    if (collective == allReadRequests) {
                        this.isReady = true;
                        this.futureDataTask.successCall(this);
                    } else {
                        Map<Integer, String> values = new HashMap<>(16);
                        collective.forEach(req ->
                                requestPointTable.get(req).forEach(point ->
                                        values.put(point.getId(), String.valueOf(point.getValue()))));
                        Map<String, Object> map = new HashMap<>(3);
                        map.put("status", CommStatus.OK.getStatus());
                        map.put("data", values);
                        reqResp(collective, map);
                    }
                }
                resetReadRequest(request, CommStatus.OK);

            } else if (responseData.getFunCode() == S7Enum.FunCode.COMM_SET) {
                this.init = true;
            }
        } else if (responseData.getCotpSectionData().getCotpType() == COTPType.ConnectConfirm) {
            COTPSectionData cotpSectionData = new COTPSectionData(COTPType.DataTransport);
            S7RequestData requestData = new S7RequestData(cotpSectionData, S7Enum.PDUType.JOB);
            requestData.setFunCode(S7Enum.FunCode.COMM_SET);
            requestData.setMaxCallee(1);
            requestData.setMaxCaller(1);
            requestData.setPduLength(1024);
            IRequest<IRequestData> iRequest = createReq(requestData);
            iRequest.flag(0, 0);
            sendRequest(Collections.singletonList(iRequest));
        }
    }

    @Override
    public void handlerWriteData(IRequest<IRequestData> request) {
        S7ResponseData responseData = (S7ResponseData) request.getResponse().getResponseData();
        if (responseData.getCotpSectionData().getCotpType() == COTPType.DataTransport) {
            if (responseData.getFunCode() == S7Enum.FunCode.WRITE) {
                for (S7DataItem dataItem : responseData.getData()) {
                    if (dataItem.getReturnCode() != S7Enum.ReturnCode.SUCCESS) {
                        CommStatus status = CommStatus.Diy;
                        status.setStatus(dataItem.getReturnCode().getMsg());
                        resetWriteRequest(status);
                        return;
                    }
                }
                List<IRequest<IRequestData>> writeRequest = request.collective();
                for (IRequest<IRequestData> req : writeRequest) {
                    if (!req.beReady()) {
                        return;
                    }
                }
                resetWriteRequest(CommStatus.OK);
            }
        }

    }

    private void s7PointValue(List<IPoint> points, List<S7DataItem> dataItems) {
        Iterator<S7DataItem> iterator = dataItems.iterator();
        S7DataItem dataItem = iterator.next();
        if (dataItem.getReturnCode() == S7Enum.ReturnCode.SUCCESS) {
            byte[] bytes = dataItem.getData();
            S7Point startPoint = (S7Point) points.get(0);
            for (IPoint ref : points) {
                S7Point point = (S7Point) ref;
                int regIdx = point.getAddress() - startPoint.getAddress();
                if (regIdx >= bytes.length) {
                    startPoint = point;
                    regIdx = point.getAddress() - startPoint.getAddress();
                    if (iterator.hasNext()) {
                        dataItem = iterator.next();
                        if (dataItem.getReturnCode() == S7Enum.ReturnCode.SUCCESS) {
                            bytes = dataItem.getData();
                        } else {
                            break;
                        }
                    } else {
                        break;
                    }
                }
                Object value = null;
                switch (point.getDataType()) {
                    case Modbus_Boolean:
                        value = ByteUtil.byteToBoolean(bytes, regIdx, point.getDeviation());
                        break;
                    case Modbus_Int8:
                        value = (int) bytes[regIdx];
                        break;
                    case Modbus_UInt8:
                        value = bytes[regIdx] & 0xff;
                        break;
                    case Modbus_Int16:
                        value = ByteUtil.byteToShort(bytes, regIdx, point.getByteOrder());
                        break;
                    case Modbus_UInt16:
                        value = ByteUtil.byteToUShort(bytes, regIdx, point.getByteOrder());
                        break;
                    case Modbus_Int32:
                        value = ByteUtil.byteToInt(bytes, regIdx, point.getByteOrder());
                        break;
                    case Modbus_UInt32:
                        value = ByteUtil.byteToUInt(bytes, regIdx, point.getByteOrder());
                        break;
                    case Modbus_Float:
                        value = ByteUtil.byteToFloat(bytes, regIdx, point.getByteOrder());
                        break;
                    case Modbus_Double:
                        value = ByteUtil.byteToDouble(bytes, regIdx, point.getByteOrder());
                    default:
                }
                point.setValue(value);
            }
        }
    }

    @Override
    public void connected() {
        COTPSectionData cotpSectionData = new COTPSectionData(COTPType.ConnectReq);
        cotpSectionData.setFlag(slaveId);
        S7RequestData requestData = new S7RequestData(cotpSectionData, null);
        IRequest<IRequestData> request = createReq(requestData);
        request.flag(0, 0);
        sendRequest(Collections.singletonList(request));
    }

}
